#include "py_app_module.h"

#include <pybind11/detail/common.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/complex.h>
#include <pybind11/chrono.h>
#include <pybind11/pytypes.h>
#include "data/editor_data.hpp"
#include "sql/types.hpp"
#include "sql/sql_data_extensions.hpp"
#include "utils/app_utils.hpp"
#include "utils/date_utils.hpp"
#include "utils/log.hpp"
#include "utils/path_utils.hpp"
#include "utils/shell_utils.hpp"
#include "scripting/extra/info_api.hpp"

namespace py = pybind11;

namespace {
    void I(py::object msg) { SendInfo(py::str(msg)); }
    void W(py::object msg) { SendWarning(py::str(msg)); }
    void E(py::object msg) { SendError(py::str(msg)); }
    void P(bool show) { ShowProgressDialog(show); }
    void N(py::object msg, double ms) { SendNotification(py::str(msg), ms); }

    void LogD(py::object msg) { std::string text = py::str(msg); log_printf("<script>", 1, LOG_LEVEL_DEBUG, "%s", text.c_str()); }
    void LogI(py::object msg) { std::string text = py::str(msg); log_printf("<script>", 1, LOG_LEVEL_INFO, "%s",  text.c_str()); }
    void LogW(py::object msg) { std::string text = py::str(msg); log_printf("<script>", 1, LOG_LEVEL_WARN, "%s",  text.c_str()); }
    void LogE(py::object msg) { std::string text = py::str(msg); log_printf("<script>", 1, LOG_LEVEL_ERROR, "%s", text.c_str()); }
}

#define CM(CLS,MEM) \
[](const CLS* x) { return x->MEM; }
#define CMRO(NAME,CLS,MEM) \
def_property_readonly(#NAME,CM(CLS,MEM))
#define PYCLS(T) pybind11::class_<T>(m, #T)

PYBIND11_MODULE(app, m) {
    PYCLS(Tag)
        .CMRO(name, Tag, tag_name)
        .CMRO(color, Tag, tag_color)
        .CMRO(level, Tag, tag_level);

    PYCLS(WorkItem)
        .CMRO(create_date, WorkItem, create_date)
        .CMRO(hour, WorkItem, hour)
        .CMRO(comment, WorkItem, comment)
        .CMRO(note, WorkItem, note)
        .CMRO(issue, WorkItem, issue_id)
        .CMRO(act, WorkItem, act_id);
    
    PYCLS(ItemNode)
        .CMRO(item, ItemNode, item)
        .CMRO(tags, ItemNode, item_tags);
    
    PYCLS(DayLevelNode)
        .def("load", [](DayLevelNode* node){ node->LoadInnerData(); })
        .CMRO(title, DayLevelNode, title)
        .CMRO(key, DayLevelNode, child_key)
        .CMRO(children, DayLevelNode, children);
    
    PYCLS(MonthLevelNode)
        .def("load", [](MonthLevelNode* node){ node->LoadInnerData(); })
        .CMRO(title, MonthLevelNode, title)
        .CMRO(key, MonthLevelNode, child_key)
        .CMRO(children, MonthLevelNode, children);

    PYCLS(YearLevelNode)
        .def("load", [](YearLevelNode* node){ node->LoadInnerData(); })
        .CMRO(title, YearLevelNode, title)
        .CMRO(key, YearLevelNode, child_key)
        .CMRO(children, YearLevelNode, children);
    
    // clipboard function
    m.def("copy_text", &CopyText)

    // version
    .def("get_app_version_str", GetAppVersionText)
    .def("get_app_version_info", GetAppVersionInfo)
    .def("get_app_version_code", GetAppVersionCode)
    .def("get_data_version_str", GetDataVersion)
    .def("get_data_version_code", GetDataVersionCode)

    // path utils
    .def("tmp_path", GetTempFilePath)
    .def("asset_path", GetAssetsPath)
    .def("data_path", GetDataPath)

    // info dialog
    .def("show_info", I)
    .def("show_warning", W)
    .def("show_error", E)
    .def("show_progress", P)

    // status message
    .def("notify", N)

    // logging
    .def("log_d", LogD)
    .def("log_i", LogI)
    .def("log_w", LogW)
    .def("log_e", LogE)

    // shell utils
    .def("choose_file", ChooseFile)
    .def("choose_files", ChooseFiles)
    .def("save_file", SaveFile)
    .def("pick_folder", PickFolder)
    .def("show_logs", ShowLogFileContent)

    // date utils
    .def("yestoday", GetYesterday)
    .def("today", GetToday)
    .def("tomorrow", GetTomorrow)

    // app utils
    .def("create_work", CreateWorkItem)
    .def("create_work_with_note", CreateWorkItemWithNote)
    .def("show_statistics", ShowStatistics)
       
    // data ext
    .def("get_issue_project_desc", sql_data_ext.get_issue_project_desc)
    ;
}

PyObject* InitAppModule()
{
    return PyInit_app();
}
